//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#include <buola/bbox/protocol/cdaemonconnection.h>
#include <buola/bbox/csession.h>
#include <buola/io/clocalendpoint.h>

namespace buola { namespace bbox { namespace protocol {

static io::PSocket connect_to_daemon()
{
    try
    {
        auto lSocket=io::connect_to(io::CAbstractLocalEndPoint("org.buola.bboxd"),io::ESocketType::PACKET);
        return lSocket;
    }
    catch(...)
    {
        msg_warn() << "can't connect to daemon!\n";
        throw XIO("can't connect to bbox daemon");
    }
}
    
CDaemonConnection::CDaemonConnection()
    :   CSyncConnection(connect_to_daemon(),get_application_name())
{
}

bool CDaemonConnection::RegisterService(const std::string &pAddress,uint64_t pUID)
{
    CStackPacket lPacket(io::nHeader,EOpcode::REGISTERSERVICE);
    lPacket << pAddress << pUID;
    auto lReply=SendPacketAndWaitReply(lPacket);
    msg_info() << "reply:" << !lReply->Header().IsError() << "\n";
    return !lReply->Header().IsError();
}

bool CDaemonConnection::UnregisterService(const std::string &pAddress)
{
    CStackPacket lPacket(io::nHeader,EOpcode::UNREGISTERSERVICE);
    lPacket << pAddress;
    auto lReply=SendPacketAndWaitReply(lPacket);
    return !lReply->Header().IsError();
}

std::pair<uint64_t,uint64_t> CDaemonConnection::GetService(const std::string &pAddress)
{
    CStackPacket lPacket(io::nHeader,EOpcode::GETSERVICE);
    lPacket << pAddress;
    auto lReply=SendPacketAndWaitReply(lPacket);
    if(lReply->Header().IsError()) return std::make_pair((uint64_t)-1,(uint64_t)-1);
    uint64_t lClient,lService;
    *lReply >> lClient >> lService;
    return std::make_pair(lClient,lService);
}

io::PSocket CDaemonConnection::ConnectToClient(uint64_t pID)
{
    CStackPacket lPacket(io::nHeader,EOpcode::CONNECTTOCLIENT);
    lPacket << pID;
    auto lReply=SendPacketAndWaitReply(lPacket);
    if(lReply->Header().IsError()) return nullptr;
    return std::move(lReply->PassSocket());
}

void CDaemonConnection::DoClientConnection(CPacket &pPacket)
{
    msg_info() << "receiving client connection!\n";
    uint64_t lOther;
    pPacket >> lOther;
    
    get_session().OnClientConnection(lOther,std::move(pPacket.PassSocket()));
}

void CDaemonConnection::OnPacket(CPacket &pPacket)
{
    switch(pPacket.Header().Major())
    {
        case EOpcode::CLIENTCONNECTION:
        DoClientConnection(pPacket);
        break;
    default:
        msg_warn() << "daemon: received unknown packet with opcode=" << (int)pPacket.Header().Major() << "... ignoring it\n";
    }
}

void CDaemonConnection::OnEOF()
{
}

/*namespace protocol*/ } /*namespace bbox*/ } /*namespace buola*/ }
